home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / network / daemons / bsd-ftpd.000 / bsd-ftpd / bsd.ftpd / ftpd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-09-09  |  35.8 KB  |  1,674 lines

  1. /*    $NetBSD: ftpd.c,v 1.15 1995/06/03 22:46:47 mycroft Exp $    */
  2.  
  3. /*
  4.  * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994
  5.  *    The Regents of the University of California.  All rights reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms, with or without
  8.  * modification, are permitted provided that the following conditions
  9.  * are met:
  10.  * 1. Redistributions of source code must retain the above copyright
  11.  *    notice, this list of conditions and the following disclaimer.
  12.  * 2. Redistributions in binary form must reproduce the above copyright
  13.  *    notice, this list of conditions and the following disclaimer in the
  14.  *    documentation and/or other materials provided with the distribution.
  15.  * 3. All advertising materials mentioning features or use of this software
  16.  *    must display the following acknowledgement:
  17.  *    This product includes software developed by the University of
  18.  *    California, Berkeley and its contributors.
  19.  * 4. Neither the name of the University nor the names of its contributors
  20.  *    may be used to endorse or promote products derived from this software
  21.  *    without specific prior written permission.
  22.  *
  23.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  24.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  25.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  26.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  27.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  28.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  29.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  30.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  31.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  32.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  33.  * SUCH DAMAGE.
  34.  */
  35.  
  36. #ifndef lint
  37. static char copyright[] =
  38. "@(#) Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994\n\
  39.     The Regents of the University of California.  All rights reserved.\n";
  40. #endif /* not lint */
  41.  
  42. #ifndef lint
  43. #if 0
  44. static char sccsid[] = "@(#)ftpd.c    8.4 (Berkeley) 4/16/94";
  45. #else
  46. static char rcsid[] = "$NetBSD: ftpd.c,v 1.15 1995/06/03 22:46:47 mycroft Exp $";
  47. #endif
  48. #endif /* not lint */
  49.  
  50. /*
  51.  * FTP server.
  52.  */
  53.  
  54. #include "glob.h"
  55.  
  56. #include <sys/param.h>
  57. #include <sys/stat.h>
  58. #include <sys/ioctl.h>
  59. #include <sys/file.h>
  60. #include <sys/socket.h>
  61. #include <sys/wait.h>
  62.  
  63. #include <netinet/in.h>
  64. #include <netinet/in_systm.h>
  65. #include <netinet/ip.h>
  66.  
  67. #define    FTP_NAMES
  68. #include <arpa/ftp.h>
  69. #include <arpa/inet.h>
  70. #include <arpa/telnet.h>
  71.  
  72. #include <ctype.h>
  73. #include <dirent.h>
  74. #include "err.h"
  75. #include <errno.h>
  76. #include <fcntl.h>
  77. #include <limits.h>
  78. #include <netdb.h>
  79. #include <pwd.h>
  80. #include <setjmp.h>
  81. #include <signal.h>
  82. #include <stdio.h>
  83. #include <stdlib.h>
  84. #include <string.h>
  85. #include <syslog.h>
  86. #include <time.h>
  87. #include <unistd.h>
  88.  
  89. #include "pathnames.h"
  90. #include "extern.h"
  91.  
  92. #if __STDC__
  93. #include <stdarg.h>
  94. #else
  95. #include <varargs.h>
  96. #endif
  97.  
  98. static char version[] = "Version 6.00/Linux";
  99.  
  100. extern    off_t restart_point;
  101. extern    char cbuf[];
  102.  
  103. struct    sockaddr_in ctrl_addr;
  104. struct    sockaddr_in data_source;
  105. struct    sockaddr_in data_dest;
  106. struct    sockaddr_in his_addr;
  107. struct    sockaddr_in pasv_addr;
  108.  
  109. int    data;
  110. jmp_buf    errcatch, urgcatch;
  111. int    logged_in;
  112. struct    passwd *pw;
  113. int    debug;
  114. int    timeout = 900;    /* timeout after 15 minutes of inactivity */
  115. int    maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */
  116. int    logging;
  117. int    guest;
  118. int    dochroot;
  119. int    type;
  120. int    form;
  121. int    stru;            /* avoid C keyword */
  122. int    mode;
  123. int    usedefault = 1;        /* for data transfers */
  124. int    pdata = -1;        /* for passive mode */
  125. sig_atomic_t transflag;
  126. off_t    file_size;
  127. off_t    byte_count;
  128. #if !defined(CMASK) || CMASK == 0
  129. #undef CMASK
  130. #define CMASK 027
  131. #endif
  132. int    defumask = CMASK;        /* default umask value */
  133. char    tmpline[7];
  134. char    hostname[MAXHOSTNAMELEN];
  135. char    remotehost[MAXHOSTNAMELEN];
  136. static char ttyline[20];
  137. char    *tty = ttyline;        /* for klogin */
  138.  
  139. char    *__progname = (char *)NULL;
  140.  
  141. #if defined(KERBEROS)
  142. int    notickets = 1;
  143. char    *krbtkfile_env = NULL;
  144. #endif 
  145.  
  146. /*
  147.  * Timeout intervals for retrying connections
  148.  * to hosts that don't accept PORT cmds.  This
  149.  * is a kludge, but given the problems with TCP...
  150.  */
  151. #define    SWAITMAX    90    /* wait at most 90 seconds */
  152. #define    SWAITINT    5    /* interval between retries */
  153.  
  154. int    swaitmax = SWAITMAX;
  155. int    swaitint = SWAITINT;
  156.  
  157. #ifndef LOG_FTP
  158. #define LOG_FTP    LOG_LOCAL5
  159. #endif
  160.  
  161. #ifdef HASSETPROCTITLE
  162. char    proctitle[BUFSIZ];    /* initial part of title */
  163. #endif /* HASSETPROCTITLE */
  164.  
  165. #define LOGCMD(cmd, file) \
  166.     if (logging > 1) \
  167.         syslog(LOG_INFO,"%s %s%s", cmd, \
  168.         *(file) == '/' ? "" : curdir(), file);
  169. #define LOGCMD2(cmd, file1, file2) \
  170.      if (logging > 1) \
  171.         syslog(LOG_INFO,"%s %s%s %s%s", cmd, \
  172.         *(file1) == '/' ? "" : curdir(), file1, \
  173.         *(file2) == '/' ? "" : curdir(), file2);
  174. #define LOGBYTES(cmd, file, cnt) \
  175.     if (logging > 1) { \
  176.         if (cnt == (off_t)-1) \
  177.             syslog(LOG_INFO,"%s %s%s", cmd, \
  178.             *(file) == '/' ? "" : curdir(), file); \
  179.         else \
  180.             syslog(LOG_INFO, "%s %s%s = %ld bytes", \
  181.             cmd, (*(file) == '/') ? "" : curdir(), file, cnt); \
  182.     }
  183.  
  184. static void     ack __P((char *));
  185. static void     myoob __P((int));
  186. static int     checkuser __P((char *, char *));
  187. static FILE    *dataconn __P((char *, off_t, char *));
  188. static void     dolog __P((struct sockaddr_in *));
  189. static char    *curdir __P((void));
  190. static void     end_login __P((void));
  191. static FILE    *getdatasock __P((char *));
  192. static char    *gunique __P((char *));
  193. static void     lostconn __P((int));
  194. static int     receive_data __P((FILE *, FILE *));
  195. static void     send_data __P((FILE *, FILE *, off_t));
  196. static struct passwd *
  197.          sgetpwnam __P((char *));
  198. static char    *sgetsave __P((char *));
  199.  
  200. static char *
  201. curdir()
  202. {
  203.     static char path[MAXPATHLEN+1+1];    /* path + '/' + '\0' */
  204.  
  205.     if (getcwd(path, sizeof(path)-2) == NULL)
  206.         return ("");
  207.     if (path[1] != '\0')        /* special case for root dir. */
  208.         strcat(path, "/");
  209.     /* For guest account, skip / since it's chrooted */
  210.     return (guest ? path+1 : path);
  211. }
  212.  
  213. int
  214. main(argc, argv, envp)
  215.     int argc;
  216.     char *argv[];
  217.     char **envp;
  218. {
  219.     int addrlen, ch, on = 1, tos;
  220.     char *cp, line[LINE_MAX];
  221.     FILE *fd;
  222.  
  223.     __progname = basename(argv[0]);
  224.  
  225.     /*
  226.      * LOG_NDELAY sets up the logging connection immediately,
  227.      * necessary for anonymous ftp's that chroot and can't do it later.
  228.      */
  229.     openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
  230.     addrlen = sizeof(his_addr);
  231.     if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) {
  232.         syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
  233.         exit(1);
  234.     }
  235.     addrlen = sizeof(ctrl_addr);
  236.     if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
  237.         syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
  238.         exit(1);
  239.     }
  240. #ifdef IP_TOS
  241.     tos = IPTOS_LOWDELAY;
  242.     if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
  243.         syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
  244. #endif
  245.     data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
  246.     debug = 0;
  247.  
  248.     /* set this here so klogin can use it... */
  249.     (void)sprintf(ttyline, "ftp%d", getpid());
  250.  
  251.     while ((ch = getopt(argc, argv, "dlt:T:u:v")) != EOF) {
  252.         switch (ch) {
  253.         case 'd':
  254.             debug = 1;
  255.             break;
  256.  
  257.         case 'l':
  258.             logging++;    /* > 1 == extra logging */
  259.             break;
  260.  
  261.         case 't':
  262.             timeout = atoi(optarg);
  263.             if (maxtimeout < timeout)
  264.                 maxtimeout = timeout;
  265.             break;
  266.  
  267.         case 'T':
  268.             maxtimeout = atoi(optarg);
  269.             if (timeout > maxtimeout)
  270.                 timeout = maxtimeout;
  271.             break;
  272.  
  273.         case 'u':
  274.             {
  275.             long val = 0;
  276.  
  277.             val = strtol(optarg, &optarg, 8);
  278.             if (*optarg != '\0' || val < 0)
  279.                 warnx("bad value for -u");
  280.             else
  281.                 defumask = val;
  282.             break;
  283.             }
  284.  
  285.         case 'v':
  286.             debug = 1;
  287.             break;
  288.  
  289.         default:
  290.             warnx("unknown flag -%c ignored", optopt);
  291.             break;
  292.         }
  293.     }
  294.     (void) freopen(_PATH_DEVNULL, "w", stderr);
  295.     (void) signal(SIGPIPE, lostconn);
  296.     (void) signal(SIGCHLD, SIG_IGN);
  297.     if ((long)signal(SIGURG, myoob) < 0)
  298.         syslog(LOG_ERR, "signal: %m");
  299.  
  300.     /* Try to handle urgent data inline */
  301. #ifdef SO_OOBINLINE
  302.     if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0)
  303.         syslog(LOG_ERR, "setsockopt: %m");
  304. #endif
  305.  
  306. #ifdef    F_SETOWN
  307.     if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
  308.         syslog(LOG_ERR, "fcntl F_SETOWN: %m");
  309. #endif
  310.     dolog(&his_addr);
  311.     /*
  312.      * Set up default state
  313.      */
  314.     data = -1;
  315.     type = TYPE_A;
  316.     form = FORM_N;
  317.     stru = STRU_F;
  318.     mode = MODE_S;
  319.     tmpline[0] = '\0';
  320.  
  321.     /* If logins are disabled, print out the message. */
  322.     if ((fd = fopen(_PATH_NOLOGIN,"r")) != NULL) {
  323.         while (fgets(line, sizeof(line), fd) != NULL) {
  324.             if ((cp = strchr(line, '\n')) != NULL)
  325.                 *cp = '\0';
  326.             lreply(530, "%s", line);
  327.         }
  328.         (void) fflush(stdout);
  329.         (void) fclose(fd);
  330.         reply(530, "System not available.");
  331.         exit(0);
  332.     }
  333.     if ((fd = fopen(_PATH_FTPWELCOME, "r")) != NULL) {
  334.         while (fgets(line, sizeof(line), fd) != NULL) {
  335.             if ((cp = strchr(line, '\n')) != NULL)
  336.                 *cp = '\0';
  337.             lreply(220, "%s", line);
  338.         }
  339.         (void) fflush(stdout);
  340.         (void) fclose(fd);
  341.         /* reply(220,) must follow */
  342.     }
  343.     (void) gethostname(hostname, sizeof(hostname));
  344.     reply(220, "%s FTP server (%s) ready.", hostname, version);
  345.     (void) setjmp(errcatch);
  346.     for (;;)
  347.         (void) yyparse();
  348.     /* NOTREACHED */
  349. }
  350.  
  351. static void
  352. lostconn(signo)
  353.     int signo;
  354. {
  355.  
  356.     if (debug)
  357.         syslog(LOG_DEBUG, "lost connection");
  358.     dologout(-1);
  359. }
  360.  
  361. /*
  362.  * Helper function for sgetpwnam().
  363.  */
  364. static char *
  365. sgetsave(s)
  366.     char *s;
  367. {
  368.     char *new = malloc((unsigned) strlen(s) + 1);
  369.  
  370.     if (new == NULL) {
  371.         perror_reply(421, "Local resource failure: malloc");
  372.         dologout(1);
  373.         /* NOTREACHED */
  374.     }
  375.     (void) strcpy(new, s);
  376.     return (new);
  377. }
  378.  
  379. /*
  380.  * Save the result of a getpwnam.  Used for USER command, since
  381.  * the data returned must not be clobbered by any other command
  382.  * (e.g., globbing).
  383.  */
  384. static struct passwd *
  385. sgetpwnam(name)
  386.     char *name;
  387. {
  388.     static struct passwd save;
  389.     struct passwd *p;
  390.  
  391.     if ((p = getpwnam(name)) == NULL)
  392.         return (p);
  393.     if (save.pw_name) {
  394.         free(save.pw_name);
  395.         free(save.pw_passwd);
  396.         free(save.pw_gecos);
  397.         free(save.pw_dir);
  398.         free(save.pw_shell);
  399.     }
  400.     save = *p;
  401.     save.pw_name = sgetsave(p->pw_name);
  402.     save.pw_passwd = sgetsave(p->pw_passwd);
  403.     save.pw_gecos = sgetsave(p->pw_gecos);
  404.     save.pw_dir = sgetsave(p->pw_dir);
  405.     save.pw_shell = sgetsave(p->pw_shell);
  406.     return (&save);
  407. }
  408.  
  409. static int login_attempts;    /* number of failed login attempts */
  410. static int askpasswd;        /* had user command, ask for passwd */
  411. static char curname[10];    /* current USER name */
  412.  
  413. /*
  414.  * USER command.
  415.  * Sets global passwd pointer pw if named account exists and is acceptable;
  416.  * sets askpasswd if a PASS command is expected.  If logged in previously,
  417.  * need to reset state.  If name is "ftp" or "anonymous", the name is not in
  418.  * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
  419.  * If account doesn't exist, ask for passwd anyway.  Otherwise, check user
  420.  * requesting login privileges.  Disallow anyone who does not have a standard
  421.  * shell as returned by getusershell().  Disallow anyone mentioned in the file
  422.  * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
  423.  */
  424. void
  425. user(name)
  426.     char *name;
  427. {
  428.     char *cp, *shell;
  429.  
  430.     if (logged_in) {
  431.         if (guest) {
  432.             reply(530, "Can't change user from guest login.");
  433.             return;
  434.         } else if (dochroot) {
  435.             reply(530, "Can't change user from chroot user.");
  436.             return;
  437.         }
  438.         end_login();
  439.     }
  440.  
  441.     guest = 0;
  442.     if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
  443.         if (checkuser(_PATH_FTPUSERS, "ftp") ||
  444.             checkuser(_PATH_FTPUSERS, "anonymous"))
  445.             reply(530, "User %s access denied.", name);
  446.         else if ((pw = sgetpwnam("ftp")) != NULL) {
  447.             guest = 1;
  448.             askpasswd = 1;
  449.             reply(331,
  450.                 "Guest login ok, type your name as password.");
  451.         } else
  452.             reply(530, "User %s unknown.", name);
  453.         if (!askpasswd && logging)
  454.             syslog(LOG_NOTICE,
  455.                 "ANONYMOUS FTP LOGIN REFUSED FROM %s", remotehost);
  456.         return;
  457.     }
  458.     if (pw = sgetpwnam(name)) {
  459.         if ((shell = pw->pw_shell) == NULL || *shell == 0)
  460.             shell = _PATH_BSHELL;
  461.         while ((cp = getusershell()) != NULL)
  462.             if (strcmp(cp, shell) == 0)
  463.                 break;
  464.         endusershell();
  465.  
  466.         if (cp == NULL || checkuser(_PATH_FTPUSERS, name)) {
  467.             reply(530, "User %s access denied.", name);
  468.             if (logging)
  469.                 syslog(LOG_NOTICE,
  470.                     "FTP LOGIN REFUSED FROM %s, %s",
  471.                     remotehost, name);
  472.             pw = (struct passwd *) NULL;
  473.             return;
  474.         }
  475.     }
  476.     if (logging)
  477.         strncpy(curname, name, sizeof(curname)-1);
  478. #ifdef SKEY
  479.     if (!skey_haskey(name)) {
  480.         char *myskey, *skey_keyinfo __P((char *name));
  481.  
  482.         myskey = skey_keyinfo(name);
  483.         reply(331, "Password [%s] for %s required.",
  484.             myskey ? myskey : "error getting challenge", name);
  485.     } else
  486. #endif
  487.         reply(331, "Password required for %s.", name);
  488.  
  489.     askpasswd = 1;
  490.     /*
  491.      * Delay before reading passwd after first failed
  492.      * attempt to slow down passwd-guessing programs.
  493.      */
  494.     if (login_attempts)
  495.         sleep((unsigned) login_attempts);
  496. }
  497.  
  498. /*
  499.  * Check if a user is in the file "fname"
  500.  */
  501. static int
  502. checkuser(fname, name)
  503.     char *fname;
  504.     char *name;
  505. {
  506.     FILE *fd;
  507.     int found = 0;
  508.     char *p, line[BUFSIZ];
  509.  
  510.     if ((fd = fopen(fname, "r")) != NULL) {
  511.         while (fgets(line, sizeof(line), fd) != NULL)
  512.             if ((p = strchr(line, '\n')) != NULL) {
  513.                 *p = '\0';
  514.                 if (line[0] == '#')
  515.                     continue;
  516.                 if (strcmp(line, name) == 0) {
  517.                     found = 1;
  518.                     break;
  519.                 }
  520.             }
  521.         (void) fclose(fd);
  522.     }
  523.     return (found);
  524. }
  525.  
  526. /*
  527.  * Terminate login as previous user, if any, resetting state;
  528.  * used when USER command is given or login fails.
  529.  */
  530. static void
  531. end_login()
  532. {
  533.  
  534.     (void) seteuid((uid_t)0);
  535.     if (logged_in)
  536.         logwtmp(ttyline, "", "");
  537.     pw = NULL;
  538.     logged_in = 0;
  539.     guest = 0;
  540.     dochroot = 0;
  541. }
  542.  
  543. void
  544. pass(passwd)
  545.     char *passwd;
  546. {
  547.     int rval;
  548.     FILE *fd;
  549.  
  550.     if (logged_in || askpasswd == 0) {
  551.         reply(503, "Login with USER first.");
  552.         return;
  553.     }
  554.     askpasswd = 0;
  555.     if (!guest) {        /* "ftp" is only account allowed no password */
  556.         if (pw == NULL) {
  557.             rval = 1;    /* failure below */
  558.             goto skip;
  559.         }
  560. #if defined(KERBEROS)
  561.         rval = klogin(pw, "", hostname, passwd);
  562.         if (rval == 0)
  563.             goto skip;
  564. #endif
  565. #ifdef SKEY
  566.         if (skey_haskey(pw->pw_name) == 0 &&
  567.            (skey_passcheck(pw->pw_name, passwd) != -1)) {
  568.             rval = 0;
  569.             goto skip;
  570.         }
  571. #endif
  572.         /* the strcmp does not catch null passwords! */
  573.         if (pw == NULL || *pw->pw_passwd == '\0' ||
  574.             strcmp(crypt(passwd, (pw ? pw->pw_passwd : "xx")), pw->pw_passwd)) {
  575.             rval = 1;     /* failure */
  576.             goto skip;
  577.         }
  578.         rval = 0;
  579.  
  580. skip:
  581.         /*
  582.          * If rval == 1, the user failed the authentication check
  583.          * above.  If rval == 0, either Kerberos or local authentication
  584.          * succeeded.
  585.          */
  586.         if (rval) {
  587.             reply(530, "Login incorrect.");
  588.             if (logging)
  589.                 syslog(LOG_NOTICE,
  590.                     "FTP LOGIN FAILED FROM %s, %s",
  591.                     remotehost, curname);
  592.             pw = NULL;
  593.             if (login_attempts++ >= 5) {
  594.                 syslog(LOG_NOTICE,
  595.                     "repeated login failures from %s",
  596.                     remotehost);
  597.                 exit(0);
  598.             }
  599.             return;
  600.         }
  601.     }
  602.     login_attempts = 0;        /* this time successful */
  603.     if (setegid((gid_t)pw->pw_gid) < 0) {
  604.         reply(550, "Can't set gid.");
  605.         return;
  606.     }
  607.     (void) initgroups(pw->pw_name, pw->pw_gid);
  608.  
  609.     /* open wtmp before chroot */
  610.     logwtmp(ttyline, pw->pw_name, remotehost);
  611.     logged_in = 1;
  612.  
  613.     dochroot = checkuser(_PATH_FTPCHROOT, pw->pw_name);
  614.     if (guest) {
  615.         /*
  616.          * We MUST do a chdir() after the chroot. Otherwise
  617.          * the old current directory will be accessible as "."
  618.          * outside the new root!
  619.          */
  620.         if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
  621.             reply(550, "Can't set guest privileges.");
  622.             goto bad;
  623.         }
  624.     } else if (dochroot) {
  625.         if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
  626.             reply(550, "Can't change root.");
  627.             goto bad;
  628.         }
  629.     } else if (chdir(pw->pw_dir) < 0) {
  630.         if (chdir("/") < 0) {
  631.             reply(530, "User %s: can't change directory to %s.",
  632.                 pw->pw_name, pw->pw_dir);
  633.             goto bad;
  634.         } else
  635.             lreply(230, "No directory! Logging in with home=/");
  636.     }
  637.     if (seteuid((uid_t)pw->pw_uid) < 0) {
  638.         reply(550, "Can't set uid.");
  639.         goto bad;
  640.     }
  641.     /*
  642.      * Display a login message, if it exists.
  643.      * N.B. reply(230,) must follow the message.
  644.      */
  645.     if ((fd = fopen(_PATH_FTPLOGINMESG, "r")) != NULL) {
  646.         char *cp, line[LINE_MAX];
  647.  
  648.         while (fgets(line, sizeof(line), fd) != NULL) {
  649.             if ((cp = strchr(line, '\n')) != NULL)
  650.                 *cp = '\0';
  651.             lreply(230, "%s", line);
  652.         }
  653.         (void) fflush(stdout);
  654.         (void) fclose(fd);
  655.     }
  656.     if (guest) {
  657.         reply(230, "Guest login ok, access restrictions apply.");
  658. #ifdef HASSETPROCTITLE
  659.         snprintf(proctitle, sizeof(proctitle),
  660.             "%s: anonymous/%.*s", remotehost,
  661.             sizeof(proctitle) - sizeof(remotehost) -
  662.             sizeof(": anonymous/"), passwd);
  663.         setproctitle(proctitle);
  664. #endif /* HASSETPROCTITLE */
  665.         if (logging)
  666.             syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s",
  667.                 remotehost, passwd);
  668.     } else {
  669.         reply(230, "User %s logged in.", pw->pw_name);
  670. #ifdef HASSETPROCTITLE
  671.         snprintf(proctitle, sizeof(proctitle),
  672.             "%s: %s", remotehost, pw->pw_name);
  673.         setproctitle(proctitle);
  674. #endif /* HASSETPROCTITLE */
  675.         if (logging)
  676.             syslog(LOG_INFO, "FTP LOGIN FROM %s as %s",
  677.                 remotehost, pw->pw_name);
  678.     }
  679.     (void) umask(defumask);
  680.     return;
  681. bad:
  682.     /* Forget all about it... */
  683.     end_login();
  684. }
  685.  
  686. void
  687. retrieve(cmd, name)
  688.     char *cmd, *name;
  689. {
  690.     FILE *fin, *dout;
  691.     struct stat st;
  692.     int (*closefunc) __P((FILE *));
  693.  
  694.     if (cmd == 0) {
  695.         fin = fopen(name, "r"), closefunc = fclose;
  696.         st.st_size = 0;
  697.     } else {
  698.         char line[BUFSIZ];
  699.  
  700.         (void) sprintf(line, cmd, name), name = line;
  701.         fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose;
  702.         st.st_size = -1;
  703.         st.st_blksize = BUFSIZ;
  704.     }
  705.     if (fin == NULL) {
  706.         if (errno != 0) {
  707.             perror_reply(550, name);
  708.             if (cmd == 0) {
  709.                 LOGCMD("get", name);
  710.             }
  711.         }
  712.         return;
  713.     }
  714.     byte_count = -1;
  715.     if (cmd == 0 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) {
  716.         reply(550, "%s: not a plain file.", name);
  717.         goto done;
  718.     }
  719.     if (restart_point) {
  720.         if (type == TYPE_A) {
  721.             off_t i, n;
  722.             int c;
  723.  
  724.             n = restart_point;
  725.             i = 0;
  726.             while (i++ < n) {
  727.                 if ((c=getc(fin)) == EOF) {
  728.                     perror_reply(550, name);
  729.                     goto done;
  730.                 }
  731.                 if (c == '\n')
  732.                     i++;
  733.             }
  734.         } else if (lseek(fileno(fin), restart_point, L_SET) < 0) {
  735.             perror_reply(550, name);
  736.             goto done;
  737.         }
  738.     }
  739.     dout = dataconn(name, st.st_size, "w");
  740.     if (dout == NULL)
  741.         goto done;
  742.     send_data(fin, dout, st.st_blksize);
  743.     (void) fclose(dout);
  744.     data = -1;
  745.     pdata = -1;
  746. done:
  747.     if (cmd == 0)
  748.         LOGBYTES("get", name, byte_count);
  749.     (*closefunc)(fin);
  750. }
  751.  
  752. void
  753. store(name, mode, unique)
  754.     char *name, *mode;
  755.     int unique;
  756. {
  757.     FILE *fout, *din;
  758.     struct stat st;
  759.     int (*closefunc) __P((FILE *));
  760.  
  761.     if (unique && stat(name, &st) == 0 &&
  762.         (name = gunique(name)) == NULL) {
  763.         LOGCMD(*mode == 'w' ? "put" : "append", name);
  764.         return;
  765.     }
  766.  
  767.     if (restart_point)
  768.         mode = "r+";
  769.     fout = fopen(name, mode);
  770.     closefunc = fclose;
  771.     if (fout == NULL) {
  772.         perror_reply(553, name);
  773.         LOGCMD(*mode == 'w' ? "put" : "append", name);
  774.         return;
  775.     }
  776.     byte_count = -1;
  777.     if (restart_point) {
  778.         if (type == TYPE_A) {
  779.             off_t i, n;
  780.             int c;
  781.  
  782.             n = restart_point;
  783.             i = 0;
  784.             while (i++ < n) {
  785.                 if ((c=getc(fout)) == EOF) {
  786.                     perror_reply(550, name);
  787.                     goto done;
  788.                 }
  789.                 if (c == '\n')
  790.                     i++;
  791.             }
  792.             /*
  793.              * We must do this seek to "current" position
  794.              * because we are changing from reading to
  795.              * writing.
  796.              */
  797.             if (fseek(fout, 0L, L_INCR) < 0) {
  798.                 perror_reply(550, name);
  799.                 goto done;
  800.             }
  801.         } else if (lseek(fileno(fout), restart_point, L_SET) < 0) {
  802.             perror_reply(550, name);
  803.             goto done;
  804.         }
  805.     }
  806.     din = dataconn(name, (off_t)-1, "r");
  807.     if (din == NULL)
  808.         goto done;
  809.     if (receive_data(din, fout) == 0) {
  810.         if (unique)
  811.             reply(226, "Transfer complete (unique file name:%s).",
  812.                 name);
  813.         else
  814.             reply(226, "Transfer complete.");
  815.     }
  816.     (void) fclose(din);
  817.     data = -1;
  818.     pdata = -1;
  819. done:
  820.     LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count);
  821.     (*closefunc)(fout);
  822. }
  823.  
  824. static FILE *
  825. getdatasock(mode)
  826.     char *mode;
  827. {
  828.     int on = 1, s, t, tries;
  829.  
  830.     if (data >= 0)
  831.         return (fdopen(data, mode));
  832.     (void) seteuid((uid_t)0);
  833.     s = socket(AF_INET, SOCK_STREAM, 0);
  834.     if (s < 0)
  835.         goto bad;
  836.     if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
  837.         (char *) &on, sizeof(on)) < 0)
  838.         goto bad;
  839.     /* anchor socket to avoid multi-homing problems */
  840.     /* data_source.sin_len = sizeof(struct sockaddr_in); */
  841.     data_source.sin_family = AF_INET;
  842.     data_source.sin_addr = ctrl_addr.sin_addr;
  843.     for (tries = 1; ; tries++) {
  844.         if (bind(s, (struct sockaddr *)&data_source,
  845.             sizeof(data_source)) >= 0)
  846.             break;
  847.         if (errno != EADDRINUSE || tries > 10)
  848.             goto bad;
  849.         sleep(tries);
  850.     }
  851.     (void) seteuid((uid_t)pw->pw_uid);
  852. #ifdef IP_TOS
  853.     on = IPTOS_THROUGHPUT;
  854.     if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
  855.         syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
  856. #endif
  857.     return (fdopen(s, mode));
  858. bad:
  859.     /* Return the real value of errno (close may change it) */
  860.     t = errno;
  861.     (void) seteuid((uid_t)pw->pw_uid);
  862.     (void) close(s);
  863.     errno = t;
  864.     return (NULL);
  865. }
  866.  
  867. static FILE *
  868. dataconn(name, size, mode)
  869.     char *name;
  870.     off_t size;
  871.     char *mode;
  872. {
  873.     char sizebuf[32];
  874.     FILE *file;
  875.     int retry = 0, tos;
  876.  
  877.     file_size = size;
  878.     byte_count = 0;
  879.     if (size != (off_t) -1)
  880.         (void) sprintf(sizebuf, " (%ld bytes)", size);
  881.     else
  882.         (void) strcpy(sizebuf, "");
  883.     if (pdata >= 0) {
  884.         struct sockaddr_in from;
  885.         int s, fromlen = sizeof(from);
  886.  
  887.         s = accept(pdata, (struct sockaddr *)&from, &fromlen);
  888.         if (s < 0) {
  889.             reply(425, "Can't open data connection.");
  890.             (void) close(pdata);
  891.             pdata = -1;
  892.             return (NULL);
  893.         }
  894.         (void) close(pdata);
  895.         pdata = s;
  896. #ifdef IP_TOS
  897.         tos = IPTOS_THROUGHPUT;
  898.         (void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos,
  899.             sizeof(int));
  900. #endif
  901.         reply(150, "Opening %s mode data connection for '%s'%s.",
  902.              type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
  903.         return (fdopen(pdata, mode));
  904.     }
  905.     if (data >= 0) {
  906.         reply(125, "Using existing data connection for '%s'%s.",
  907.             name, sizebuf);
  908.         usedefault = 1;
  909.         return (fdopen(data, mode));
  910.     }
  911.     if (usedefault)
  912.         data_dest = his_addr;
  913.     usedefault = 1;
  914.     file = getdatasock(mode);
  915.     if (file == NULL) {
  916.         reply(425, "Can't create data socket (%s,%d): %s.",
  917.             inet_ntoa(data_source.sin_addr),
  918.             ntohs(data_source.sin_port), strerror(errno));
  919.         return (NULL);
  920.     }
  921.     data = fileno(file);
  922.     while (connect(data, (struct sockaddr *)&data_dest,
  923.         sizeof(data_dest)) < 0) {
  924.         if (errno == EADDRINUSE && retry < swaitmax) {
  925.             sleep((unsigned) swaitint);
  926.             retry += swaitint;
  927.             continue;
  928.         }
  929.         perror_reply(425, "Can't build data connection");
  930.         (void) fclose(file);
  931.         data = -1;
  932.         return (NULL);
  933.     }
  934.     reply(150, "Opening %s mode data connection for '%s'%s.",
  935.          type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
  936.     return (file);
  937. }
  938.  
  939. /*
  940.  * Tranfer the contents of "instr" to "outstr" peer using the appropriate
  941.  * encapsulation of the data subject * to Mode, Structure, and Type.
  942.  *
  943.  * NB: Form isn't handled.
  944.  */
  945. static void
  946. send_data(instr, outstr, blksize)
  947.     FILE *instr, *outstr;
  948.     off_t blksize;
  949. {
  950.     int c, cnt, filefd, netfd;
  951.     char *buf;
  952.  
  953.     transflag++;
  954.     if (setjmp(urgcatch)) {
  955.         transflag = 0;
  956.         return;
  957.     }
  958.     switch (type) {
  959.  
  960.     case TYPE_A:
  961.         while ((c = getc(instr)) != EOF) {
  962.             byte_count++;
  963.             if (c == '\n') {
  964.                 if (ferror(outstr))
  965.                     goto data_err;
  966.                 (void) putc('\r', outstr);
  967.             }
  968.             (void) putc(c, outstr);
  969.         }
  970.         fflush(outstr);
  971.         transflag = 0;
  972.         if (ferror(instr))
  973.             goto file_err;
  974.         if (ferror(outstr))
  975.             goto data_err;
  976.         reply(226, "Transfer complete.");
  977.         return;
  978.  
  979.     case TYPE_I:
  980.     case TYPE_L:
  981.         if ((buf = malloc((u_int)blksize)) == NULL) {
  982.             transflag = 0;
  983.             perror_reply(451, "Local resource failure: malloc");
  984.             return;
  985.         }
  986.         netfd = fileno(outstr);
  987.         filefd = fileno(instr);
  988.         while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 &&
  989.             write(netfd, buf, cnt) == cnt)
  990.             byte_count += cnt;
  991.         transflag = 0;
  992.         (void)free(buf);
  993.         if (cnt != 0) {
  994.             if (cnt < 0)
  995.                 goto file_err;
  996.             goto data_err;
  997.         }
  998.         reply(226, "Transfer complete.");
  999.         return;
  1000.     default:
  1001.         transflag = 0;
  1002.         reply(550, "Unimplemented TYPE %d in send_data", type);
  1003.         return;
  1004.     }
  1005.  
  1006. data_err:
  1007.     transflag = 0;
  1008.     perror_reply(426, "Data connection");
  1009.     return;
  1010.  
  1011. file_err:
  1012.     transflag = 0;
  1013.     perror_reply(551, "Error on input file");
  1014. }
  1015.  
  1016. /*
  1017.  * Transfer data from peer to "outstr" using the appropriate encapulation of
  1018.  * the data subject to Mode, Structure, and Type.
  1019.  *
  1020.  * N.B.: Form isn't handled.
  1021.  */
  1022. static int
  1023. receive_data(instr, outstr)
  1024.     FILE *instr, *outstr;
  1025. {
  1026.     int c;
  1027.     int cnt, bare_lfs = 0;
  1028.     char buf[BUFSIZ];
  1029.  
  1030.     transflag++;
  1031.     if (setjmp(urgcatch)) {
  1032.         transflag = 0;
  1033.         return (-1);
  1034.     }
  1035.     switch (type) {
  1036.  
  1037.     case TYPE_I:
  1038.     case TYPE_L:
  1039.         while ((cnt = read(fileno(instr), buf, sizeof(buf))) > 0) {
  1040.             if (write(fileno(outstr), buf, cnt) != cnt)
  1041.                 goto file_err;
  1042.             byte_count += cnt;
  1043.         }
  1044.         if (cnt < 0)
  1045.             goto data_err;
  1046.         transflag = 0;
  1047.         return (0);
  1048.  
  1049.     case TYPE_E:
  1050.         reply(553, "TYPE E not implemented.");
  1051.         transflag = 0;
  1052.         return (-1);
  1053.  
  1054.     case TYPE_A:
  1055.         while ((c = getc(instr)) != EOF) {
  1056.             byte_count++;
  1057.             if (c == '\n')
  1058.                 bare_lfs++;
  1059.             while (c == '\r') {
  1060.                 if (ferror(outstr))
  1061.                     goto data_err;
  1062.                 if ((c = getc(instr)) != '\n') {
  1063.                     (void) putc ('\r', outstr);
  1064.                     if (c == '\0' || c == EOF)
  1065.                         goto contin2;
  1066.                 }
  1067.             }
  1068.             (void) putc(c, outstr);
  1069.     contin2:    ;
  1070.         }
  1071.         fflush(outstr);
  1072.         if (ferror(instr))
  1073.             goto data_err;
  1074.         if (ferror(outstr))
  1075.             goto file_err;
  1076.         transflag = 0;
  1077.         if (bare_lfs) {
  1078.             lreply(226,
  1079.         "WARNING! %d bare linefeeds received in ASCII mode",
  1080.                 bare_lfs);
  1081.         (void)printf("   File may not have transferred correctly.\r\n");
  1082.         }
  1083.         return (0);
  1084.     default:
  1085.         reply(550, "Unimplemented TYPE %d in receive_data", type);
  1086.         transflag = 0;
  1087.         return (-1);
  1088.     }
  1089.  
  1090. data_err:
  1091.     transflag = 0;
  1092.     perror_reply(426, "Data Connection");
  1093.     return (-1);
  1094.  
  1095. file_err:
  1096.     transflag = 0;
  1097.     perror_reply(452, "Error writing file");
  1098.     return (-1);
  1099. }
  1100.  
  1101. void
  1102. statfilecmd(filename)
  1103.     char *filename;
  1104. {
  1105.     FILE *fin;
  1106.     int c;
  1107.     char line[LINE_MAX];
  1108.  
  1109.     (void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename);
  1110.     fin = ftpd_popen(line, "r");
  1111.     lreply(211, "status of %s:", filename);
  1112.     while ((c = getc(fin)) != EOF) {
  1113.         if (c == '\n') {
  1114.             if (ferror(stdout)){
  1115.                 perror_reply(421, "control connection");
  1116.                 (void) ftpd_pclose(fin);
  1117.                 dologout(1);
  1118.                 /* NOTREACHED */
  1119.             }
  1120.             if (ferror(fin)) {
  1121.                 perror_reply(551, filename);
  1122.                 (void) ftpd_pclose(fin);
  1123.                 return;
  1124.             }
  1125.             (void) putc('\r', stdout);
  1126.         }
  1127.         (void) putc(c, stdout);
  1128.     }
  1129.     (void) ftpd_pclose(fin);
  1130.     reply(211, "End of Status");
  1131. }
  1132.  
  1133. void
  1134. statcmd()
  1135. {
  1136.     struct sockaddr_in *sin;
  1137.     u_char *a, *p;
  1138.  
  1139.     lreply(211, "%s FTP server status:", hostname, version);
  1140.     printf("     %s\r\n", version);
  1141.     printf("     Connected to %s", remotehost);
  1142.     if (!isdigit(remotehost[0]))
  1143.         printf(" (%s)", inet_ntoa(his_addr.sin_addr));
  1144.     printf("\r\n");
  1145.     if (logged_in) {
  1146.         if (guest)
  1147.             printf("     Logged in anonymously\r\n");
  1148.         else
  1149.             printf("     Logged in as %s\r\n", pw->pw_name);
  1150.     } else if (askpasswd)
  1151.         printf("     Waiting for password\r\n");
  1152.     else
  1153.         printf("     Waiting for user name\r\n");
  1154.     printf("     TYPE: %s", typenames[type]);
  1155.     if (type == TYPE_A || type == TYPE_E)
  1156.         printf(", FORM: %s", formnames[form]);
  1157.     if (type == TYPE_L)
  1158. #if CHAR_BIT == 8
  1159.         printf(" %d", CHAR_BIT);
  1160. #else
  1161.         printf(" %d", bytesize);    /* need definition! */
  1162. #endif
  1163.     printf("; STRUcture: %s; transfer MODE: %s\r\n",
  1164.         strunames[stru], modenames[mode]);
  1165.     if (data != -1)
  1166.         printf("     Data connection open\r\n");
  1167.     else if (pdata != -1) {
  1168.         printf("     in Passive mode");
  1169.         sin = &pasv_addr;
  1170.         goto printaddr;
  1171.     } else if (usedefault == 0) {
  1172.         printf("     PORT");
  1173.         sin = &data_dest;
  1174. printaddr:
  1175.         a = (u_char *) &sin->sin_addr;
  1176.         p = (u_char *) &sin->sin_port;
  1177. #define UC(b) (((int) b) & 0xff)
  1178.         printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]),
  1179.             UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
  1180. #undef UC
  1181.     } else
  1182.         printf("     No data connection\r\n");
  1183.     reply(211, "End of status");
  1184. }
  1185.  
  1186. void
  1187. fatal(s)
  1188.     char *s;
  1189. {
  1190.  
  1191.     reply(451, "Error in server: %s\n", s);
  1192.     reply(221, "Closing connection due to server error.");
  1193.     dologout(0);
  1194.     /* NOTREACHED */
  1195. }
  1196.  
  1197. void
  1198. #if __STDC__
  1199. reply(int n, const char *fmt, ...)
  1200. #else
  1201. reply(n, fmt, va_alist)
  1202.     int n;
  1203.     char *fmt;
  1204.         va_dcl
  1205. #endif
  1206. {
  1207.     va_list ap;
  1208. #if __STDC__
  1209.     va_start(ap, fmt);
  1210. #else
  1211.     va_start(ap);
  1212. #endif
  1213.     (void)printf("%d ", n);
  1214.     (void)vprintf(fmt, ap);
  1215.     (void)printf("\r\n");
  1216.     (void)fflush(stdout);
  1217.     if (debug) {
  1218.         syslog(LOG_DEBUG, "<--- %d ", n);
  1219.         vsyslog(LOG_DEBUG, fmt, ap);
  1220.     }
  1221. }
  1222.  
  1223. void
  1224. #if __STDC__
  1225. lreply(int n, const char *fmt, ...)
  1226. #else
  1227. lreply(n, fmt, va_alist)
  1228.     int n;
  1229.     char *fmt;
  1230.         va_dcl
  1231. #endif
  1232. {
  1233.     va_list ap;
  1234. #if __STDC__
  1235.     va_start(ap, fmt);
  1236. #else
  1237.     va_start(ap);
  1238. #endif
  1239.     (void)printf("%d- ", n);
  1240.     (void)vprintf(fmt, ap);
  1241.     (void)printf("\r\n");
  1242.     (void)fflush(stdout);
  1243.     if (debug) {
  1244.         syslog(LOG_DEBUG, "<--- %d- ", n);
  1245.         vsyslog(LOG_DEBUG, fmt, ap);
  1246.     }
  1247. }
  1248.  
  1249. static void
  1250. ack(s)
  1251.     char *s;
  1252. {
  1253.  
  1254.     reply(250, "%s command successful.", s);
  1255. }
  1256.  
  1257. void
  1258. nack(s)
  1259.     char *s;
  1260. {
  1261.  
  1262.     reply(502, "%s command not implemented.", s);
  1263. }
  1264.  
  1265. /* ARGSUSED */
  1266. void
  1267. yyerror(s)
  1268.     char *s;
  1269. {
  1270.     char *cp;
  1271.  
  1272.     if (cp = strchr(cbuf,'\n'))
  1273.         *cp = '\0';
  1274.     reply(500, "'%s': command not understood.", cbuf);
  1275. }
  1276.  
  1277. void
  1278. delete(name)
  1279.     char *name;
  1280. {
  1281.     struct stat st;
  1282.  
  1283.     LOGCMD("delete", name);
  1284.     if (stat(name, &st) < 0) {
  1285.         perror_reply(550, name);
  1286.         return;
  1287.     }
  1288.     if ((st.st_mode&S_IFMT) == S_IFDIR) {
  1289.         if (rmdir(name) < 0) {
  1290.             perror_reply(550, name);
  1291.             return;
  1292.         }
  1293.         goto done;
  1294.     }
  1295.     if (unlink(name) < 0) {
  1296.         perror_reply(550, name);
  1297.         return;
  1298.     }
  1299. done:
  1300.     ack("DELE");
  1301. }
  1302.  
  1303. void
  1304. cwd(path)
  1305.     char *path;
  1306. {
  1307.  
  1308.     if (chdir(path) < 0)
  1309.         perror_reply(550, path);
  1310.     else
  1311.         ack("CWD");
  1312. }
  1313.  
  1314. void
  1315. makedir(name)
  1316.     char *name;
  1317. {
  1318.  
  1319.     LOGCMD("mkdir", name);
  1320.     if (mkdir(name, 0777) < 0)
  1321.         perror_reply(550, name);
  1322.     else
  1323.         reply(257, "MKD command successful.");
  1324. }
  1325.  
  1326. void
  1327. removedir(name)
  1328.     char *name;
  1329. {
  1330.  
  1331.     LOGCMD("rmdir", name);
  1332.     if (rmdir(name) < 0)
  1333.         perror_reply(550, name);
  1334.     else
  1335.         ack("RMD");
  1336. }
  1337.  
  1338. void
  1339. pwd()
  1340. {
  1341.     char path[MAXPATHLEN + 1];
  1342.  
  1343.     if (getwd(path) == (char *)NULL)
  1344.         reply(550, "%s.", path);
  1345.     else
  1346.         reply(257, "\"%s\" is current directory.", path);
  1347. }
  1348.  
  1349. char *
  1350. renamefrom(name)
  1351.     char *name;
  1352. {
  1353.     struct stat st;
  1354.  
  1355.     if (stat(name, &st) < 0) {
  1356.         perror_reply(550, name);
  1357.         return ((char *)0);
  1358.     }
  1359.     reply(350, "File exists, ready for destination name");
  1360.     return (name);
  1361. }
  1362.  
  1363. void
  1364. renamecmd(from, to)
  1365.     char *from, *to;
  1366. {
  1367.  
  1368.     LOGCMD2("rename", from, to);
  1369.     if (rename(from, to) < 0)
  1370.         perror_reply(550, "rename");
  1371.     else
  1372.         ack("RNTO");
  1373. }
  1374.  
  1375. static void
  1376. dolog(sin)
  1377.     struct sockaddr_in *sin;
  1378. {
  1379.     struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr,
  1380.         sizeof(struct in_addr), AF_INET);
  1381.  
  1382.     if (hp)
  1383.         (void) strncpy(remotehost, hp->h_name, sizeof(remotehost));
  1384.     else
  1385.         (void) strncpy(remotehost, inet_ntoa(sin->sin_addr),
  1386.             sizeof(remotehost));
  1387. #ifdef HASSETPROCTITLE
  1388.     snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
  1389.     setproctitle(proctitle);
  1390. #endif /* HASSETPROCTITLE */
  1391.  
  1392.     if (logging)
  1393.         syslog(LOG_INFO, "connection from %s", remotehost);
  1394. }
  1395.  
  1396. /*
  1397.  * Record logout in wtmp file
  1398.  * and exit with supplied status.
  1399.  */
  1400. void
  1401. dologout(status)
  1402.     int status;
  1403. {
  1404.  
  1405.     if (logged_in) {
  1406.         (void) seteuid((uid_t)0);
  1407.         logwtmp(ttyline, "", "");
  1408. #if defined(KERBEROS)
  1409.         if (!notickets && krbtkfile_env)
  1410.             unlink(krbtkfile_env);
  1411. #endif
  1412.     }
  1413.     /* beware of flushing buffers after a SIGPIPE */
  1414.     _exit(status);
  1415. }
  1416.  
  1417. static void
  1418. myoob(signo)
  1419.     int signo;
  1420. {
  1421.     char *cp;
  1422.  
  1423.     /* only process if transfer occurring */
  1424.     if (!transflag)
  1425.         return;
  1426.     cp = tmpline;
  1427.     if (getline(cp, 7, stdin) == NULL) {
  1428.         reply(221, "You could at least say goodbye.");
  1429.         dologout(0);
  1430.     }
  1431.     upper(cp);
  1432.     if (strcmp(cp, "ABOR\r\n") == 0) {
  1433.         tmpline[0] = '\0';
  1434.         reply(426, "Transfer aborted. Data connection closed.");
  1435.         reply(226, "Abort successful");
  1436.         longjmp(urgcatch, 1);
  1437.     }
  1438.     if (strcmp(cp, "STAT\r\n") == 0) {
  1439.         if (file_size != (off_t) -1)
  1440.             reply(213, "Status: %ld of %ld bytes transferred",
  1441.                 byte_count, file_size);
  1442.         else
  1443.             reply(213, "Status: %ld bytes transferred", byte_count);
  1444.     }
  1445. }
  1446.  
  1447. /*
  1448.  * Note: a response of 425 is not mentioned as a possible response to
  1449.  *    the PASV command in RFC959. However, it has been blessed as
  1450.  *    a legitimate response by Jon Postel in a telephone conversation
  1451.  *    with Rick Adams on 25 Jan 89.
  1452.  */
  1453. void
  1454. passive()
  1455. {
  1456.     int len;
  1457.     char *p, *a;
  1458.  
  1459.     pdata = socket(AF_INET, SOCK_STREAM, 0);
  1460.     if (pdata < 0) {
  1461.         perror_reply(425, "Can't open passive connection");
  1462.         return;
  1463.     }
  1464.     pasv_addr = ctrl_addr;
  1465.     pasv_addr.sin_port = 0;
  1466.     (void) seteuid((uid_t)0);
  1467.     if (bind(pdata, (struct sockaddr *)&pasv_addr, sizeof(pasv_addr)) < 0) {
  1468.         (void) seteuid((uid_t)pw->pw_uid);
  1469.         goto pasv_error;
  1470.     }
  1471.     (void) seteuid((uid_t)pw->pw_uid);
  1472.     len = sizeof(pasv_addr);
  1473.     if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
  1474.         goto pasv_error;
  1475.     if (listen(pdata, 1) < 0)
  1476.         goto pasv_error;
  1477.     a = (char *) &pasv_addr.sin_addr;
  1478.     p = (char *) &pasv_addr.sin_port;
  1479.  
  1480. #define UC(b) (((int) b) & 0xff)
  1481.  
  1482.     reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
  1483.         UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
  1484.     return;
  1485.  
  1486. pasv_error:
  1487.     (void) close(pdata);
  1488.     pdata = -1;
  1489.     perror_reply(425, "Can't open passive connection");
  1490.     return;
  1491. }
  1492.  
  1493. /*
  1494.  * Generate unique name for file with basename "local".
  1495.  * The file named "local" is already known to exist.
  1496.  * Generates failure reply on error.
  1497.  */
  1498. static char *
  1499. gunique(local)
  1500.     char *local;
  1501. {
  1502.     static char new[MAXPATHLEN];
  1503.     struct stat st;
  1504.     int count;
  1505.     char *cp;
  1506.  
  1507.     cp = strrchr(local, '/');
  1508.     if (cp)
  1509.         *cp = '\0';
  1510.     if (stat(cp ? local : ".", &st) < 0) {
  1511.         perror_reply(553, cp ? local : ".");
  1512.         return ((char *) 0);
  1513.     }
  1514.     if (cp)
  1515.         *cp = '/';
  1516.     (void) strcpy(new, local);
  1517.     cp = new + strlen(new);
  1518.     *cp++ = '.';
  1519.     for (count = 1; count < 100; count++) {
  1520.         (void)sprintf(cp, "%d", count);
  1521.         if (stat(new, &st) < 0)
  1522.             return (new);
  1523.     }
  1524.     reply(452, "Unique file name cannot be created.");
  1525.     return (NULL);
  1526. }
  1527.  
  1528. /*
  1529.  * Format and send reply containing system error number.
  1530.  */
  1531. void
  1532. perror_reply(code, string)
  1533.     int code;
  1534.     char *string;
  1535. {
  1536.  
  1537.     reply(code, "%s: %s.", string, strerror(errno));
  1538. }
  1539.  
  1540. static char *onefile[] = {
  1541.     "",
  1542.     0
  1543. };
  1544.  
  1545. void
  1546. send_file_list(whichf)
  1547.     char *whichf;
  1548. {
  1549.     struct stat st;
  1550.     DIR *dirp = NULL;
  1551.     struct dirent *dir;
  1552.     FILE *dout = NULL;
  1553.     char **dirlist, *dirname;
  1554.     int simple = 0;
  1555.     int freeglob = 0;
  1556.     glob_t gl;
  1557.  
  1558.     if (strpbrk(whichf, "~{[*?") != NULL) {
  1559.         int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
  1560.  
  1561.         memset(&gl, 0, sizeof(gl));
  1562.         freeglob = 1;
  1563.         if (glob(whichf, flags, 0, &gl)) {
  1564.             reply(550, "not found");
  1565.             goto out;
  1566.         } else if (gl.gl_pathc == 0) {
  1567.             errno = ENOENT;
  1568.             perror_reply(550, whichf);
  1569.             goto out;
  1570.         }
  1571.         dirlist = gl.gl_pathv;
  1572.     } else {
  1573.         onefile[0] = whichf;
  1574.         dirlist = onefile;
  1575.         simple = 1;
  1576.     }
  1577.  
  1578.     if (setjmp(urgcatch)) {
  1579.         transflag = 0;
  1580.         goto out;
  1581.     }
  1582.     while (dirname = *dirlist++) {
  1583.         if (stat(dirname, &st) < 0) {
  1584.             /*
  1585.              * If user typed "ls -l", etc, and the client
  1586.              * used NLST, do what the user meant.
  1587.              */
  1588.             if (dirname[0] == '-' && *dirlist == NULL &&
  1589.                 transflag == 0) {
  1590.                 retrieve("/bin/ls %s", dirname);
  1591.                 goto out;
  1592.             }
  1593.             perror_reply(550, whichf);
  1594.             if (dout != NULL) {
  1595.                 (void) fclose(dout);
  1596.                 transflag = 0;
  1597.                 data = -1;
  1598.                 pdata = -1;
  1599.             }
  1600.             goto out;
  1601.         }
  1602.  
  1603.         if (S_ISREG(st.st_mode)) {
  1604.             if (dout == NULL) {
  1605.                 dout = dataconn("file list", (off_t)-1, "w");
  1606.                 if (dout == NULL)
  1607.                     goto out;
  1608.                 transflag++;
  1609.             }
  1610.             fprintf(dout, "%s%s\n", dirname,
  1611.                 type == TYPE_A ? "\r" : "");
  1612.             byte_count += strlen(dirname) + 1;
  1613.             continue;
  1614.         } else if (!S_ISDIR(st.st_mode))
  1615.             continue;
  1616.  
  1617.         if ((dirp = opendir(dirname)) == NULL)
  1618.             continue;
  1619.  
  1620.         while ((dir = readdir(dirp)) != NULL) {
  1621.             char nbuf[MAXPATHLEN];
  1622.  
  1623.             if (dir->d_name[0] == '.' && dir->d_namlen == 1)
  1624.                 continue;
  1625.             if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
  1626.                 dir->d_namlen == 2)
  1627.                 continue;
  1628.  
  1629.             sprintf(nbuf, "%s/%s", dirname, dir->d_name);
  1630.  
  1631.             /*
  1632.              * We have to do a stat to insure it's
  1633.              * not a directory or special file.
  1634.              */
  1635.             if (simple || (stat(nbuf, &st) == 0 &&
  1636.                 S_ISREG(st.st_mode))) {
  1637.                 if (dout == NULL) {
  1638.                     dout = dataconn("file list", (off_t)-1,
  1639.                         "w");
  1640.                     if (dout == NULL)
  1641.                         goto out;
  1642.                     transflag++;
  1643.                 }
  1644.                 if (nbuf[0] == '.' && nbuf[1] == '/')
  1645.                     fprintf(dout, "%s%s\n", &nbuf[2],
  1646.                         type == TYPE_A ? "\r" : "");
  1647.                 else
  1648.                     fprintf(dout, "%s%s\n", nbuf,
  1649.                         type == TYPE_A ? "\r" : "");
  1650.                 byte_count += strlen(nbuf) + 1;
  1651.             }
  1652.         }
  1653.         (void) closedir(dirp);
  1654.     }
  1655.  
  1656.     if (dout == NULL)
  1657.         reply(550, "No files found.");
  1658.     else if (ferror(dout) != 0)
  1659.         perror_reply(550, "Data connection");
  1660.     else
  1661.         reply(226, "Transfer complete.");
  1662.  
  1663.     transflag = 0;
  1664.     if (dout != NULL)
  1665.         (void) fclose(dout);
  1666.     data = -1;
  1667.     pdata = -1;
  1668. out:
  1669.     if (freeglob) {
  1670.         freeglob = 0;
  1671.         globfree(&gl);
  1672.     }
  1673. }
  1674.